package com.song.springclouddemoshardingjdbc.controller;

import com.song.springclouddemoshardingjdbc.entity.Pager;
import com.song.springclouddemoshardingjdbc.entity.User;
import com.song.springclouddemoshardingjdbc.mapper.UserMapper;
import com.song.springclouddemoshardingjdbc.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.*;


/*

    需求场景：
        user表单表数据量达到 1000w 以上了，后续数据量也会递增，user 单表字段 < 30，表字段不多，但是qps大，查询慢
    解决方案：
        方案1：直接分表
            分表策略：（指定分片键、分片算法）
                1）根据 user 表的 id 主键均衡分表，分在3个表中 user0, user1, user2 中，查询所有用户时，返回的结果是所有分表的 笛卡尔积 （所有分表数据和）
                2）结合业务进行分表，比如：根据不同年份、月份创建的用户分表、or 按照 用户工号奇偶性 分表等
                注意：分片键最好选用数值型，不要选用字符型，因为数值型的分片算法更好实现
    实现过程：
        step1；主库中建新的分表 user0, user1, user2（主库建了从库会自动创建）、分表配置
        step2：迁移历史数据（将历史数据按照 分片键、分片算法，迁移到分表中 SQL按条件查询，插入到新表）
        step3：删除 user 旧表（可跳过，暂时作为备份保存）



    ShardingJDBC实现分库分表总结：
         前提：
            Mysql实现主从复制： 主：3306  从：3307、3308、3009
            不能将ShardingJDBC读写分离和分库分表混合使用
         注意：
            1）检查主键是否有重复生成！
            分库分表后，查询出来的结果可以看到，Integer(java) --> int(mysql) 自增 类型主键会出现重复的结果
            解决办法：配置表的主键生成算法：雪花算法（推荐）、UUID
                    雪花算法： 主键 long(java) --> bigint(mysql), 必须取消 主键自增 设置，设置成自增长列就会插不进入
                    UUID: 主键 String(java) --> varchar(mysql)，必须取消 主键自增 设置，设置成自增长列就会插不进入
            2）分表后检查下分页查询是否有坑！   好像代码分页会出现oom，但是自测没有测到过

 */

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserMapper userMapper;


    // 读写分离测试
    // http://localhost:8888/user/save
    @GetMapping("/save")
    public String insert() {
        User user = new User();
        user.setNickname("zhangsan" + new Random().nextInt());
        user.setPassword("1234567");
        user.setSex(1);
        userMapper.addUser(user);
        return "success";
    }


    // 读写分离测试
    // 无分页
    // http://localhost:8888/user/listuser
    @GetMapping("/listuser")
    public List<User> listUser() {
        return userMapper.findUsers();
    }



    // 分表测试
    // 有分页
    // http://localhost:8888/user/listUserPager?page=1&size=2
    @GetMapping("/listUserPager")
    public Pager<User> listUserPager(int page, int size){
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("page", (page-1)*size);  //当前页号
        params.put("size", size);  //每页大小
        List<User> list = userMapper.findUserByPage(params);
        Pager<User> pager = new Pager<User>();
        pager.setPage(page);
        pager.setSize(size);
        pager.setData(list);
        pager.setTotal(userMapper.findUserCount());
        return pager;
    }


    // 分库测试   分库分表测试
    // 按照性别分别存在2个库  age<=30 db1、 30<age<=60 db2、 age>60 db3
    // http://localhost:8888/user/saveUsers
    @GetMapping("/saveUsers")
    public String saveUsers(){
        List<User> userList = new ArrayList();
        User user1 = new User(){{setNickname("amamisan" + new Random().nextInt()); setPassword("1234567"); setSex(0); setAge(10); setBirthday(DateUtils.parseDate("2023-12-03")); setDbname("test");}};
        User user2 = new User(){{setNickname("amamisan" + new Random().nextInt()); setPassword("1234567"); setSex(1); setAge(50); setBirthday(DateUtils.parseDate("2024-12-03")); setDbname("prod");}};
        User user3 = new User(){{setNickname("amamisan" + new Random().nextInt()); setPassword("1234567"); setSex(0); setAge(80); setBirthday(DateUtils.parseDate("2020-12-03")); setDbname("test");}};
        User user4 = new User(){{setNickname("amamisan" + new Random().nextInt()); setPassword("1234567"); setSex(0); setAge(30); setBirthday(DateUtils.parseDate("2021-12-03")); setDbname("test");}};
        User user6= new User(){{setNickname("amamisan" + new Random().nextInt()); setPassword("1234567"); setSex(0); setAge(30); setBirthday(DateUtils.parseDate("2023-01-01")); setDbname("prod");}};
        User user5 = new User(){{setNickname("amamisan" + new Random().nextInt()); setPassword("1234567"); setSex(0); setAge(60); setBirthday(new Date()); setDbname("test");}};
        userList.add(user1);
        userList.add(user2);
        userList.add(user3);
        userList.add(user4);
        userList.add(user5);
        userList.add(user6);

        for (User user : userList) {
            userMapper.addUser(user);
        }
        return "success";
    }

}
